import { sequelize, Notification, User } from '../models'
import * as $wechat from './wechat'
import dayjs from 'dayjs'
import CONFIG from '../config'

/**
 * Create a notication slot with formId
 * @param {string} formId
 * @param {int} userId
 * @return {object} Notification
 */
export const create = async (formId, userId) => {
  if (formId.indexOf('mock') != -1) {
    console.log(formId)
    return null
  }
  const user = await User.findById(userId)
  if (user == null) {
    throw new Error(`${ERRORS.DBERR.ERR_RECORD_NOT_FOUND}`)
  }
  let openId = user.openId
  return await Notification.create({
    formId,
    openId,
    userId
  })
}

/**
 * Find and Remove an existing notification slot
 * @param {int} userId
 * @param {int} targetId
 * @param {enum} scope
 * @return {object} Notification
 */
export const findAndRemove = async (userId, targetId, scope) => {
  let notification = await Notification.findOne({
    where: {
      userId,
      createdAt: {
        $gte: new Date(new Date() - 7 * 24 * 60 * 60 * 1000)
      }
    },
    order: [['createdAt', 'ASC']]
  })

  if (notification) {
    notification.targetId = targetId
    notification.scope = scope
    notification.deletedAt = new Date()
    notification.save().then(result => {
      result.destroy()
    })
  }
  return notification
}

// export const cleanExpireData = async () => {
//   let lastWeekBefore = dayjs().substract(7, 'days')
//   let flag = await Notification.destroy({
//     where: {
//       createdAt: {
//         $gte: new Date(new Date() - 7 * 24 * 60 * 60 * 1000)
//       }
//     }
//   })
//   return flag
// }


export const findOneNotification = async (userId) => {
  let lastWeekBefore = dayjs().subtract(7, 'days')
  let notification = await Notification.findOne({
    where: {
      userId,
      createdAt: {
        $gte: lastWeekBefore.format('YYYY-MM-DD HH:mm:ss')
      }
    },
    order: [['createdAt', 'ASC']]
  })
  return notification
}

/**
 * Send template message to a user using wechat
 * @param {object} data
 * @param {object} target
 * @return {object} Notification
 */
export const sendNotification = async (
  { title, data, url } = data,
  { userId } = target
) => {
  let notification = await findOneNotification(userId)
  let template = CONFIG.wechat.templates[title]

  if (!notification || !template) return false

  console.log('Sending notification to ' + notification.openId, '---', userId)
  await $wechat.sendTemplateMessage(
    notification.openId,
    notification.formId,
    template.id,
    url,
    data
  )
  await Notification.destroy({
    where: {
      id: notification.id
    },
    force: true
  })
  return true
}

/**
 * Find and Remove an existing notification slot
 * @param {array} targets
 * @return {object} Notification
 */
export const findByUserIds = async targets => {
  let userIds = Object.keys(targets)

  // Find all available notification slots
  let notifications = await Notification.findAll({
    attributes: [
      'userId',
      'formId',
      'openId',
      [sequelize.fn('MIN', sequelize.col('id')), 'id']
    ],
    where: {
      userId: { $in: userIds },
      createdAt: {
        $gte: new Date(new Date() - 7 * 24 * 60 * 60 * 1000)
      }
    },
    group: ['userId']
  })

  // Find all notification slots used in the past 24 hours
  /*
  let excluded = await Notification.findAll({
    attributes: ['userId'],
    where: {
      userId: { $in: userIds },
      deletedAt: {
        $gte: new Date(new Date() - 1 * 24 * 60 * 60 * 1000)
      }
    },
    group: ['userId'],
    paranoid: false
  })

  let excludedUserIds = new Set(
    excluded.map(({ userId }) => {
      return userId
    })
  )

  // remove those notified in 24 hours
  notifications = notifications.filter(el => !excludedUserIds.has(el.userId))
  */
  // update and delete notifications
  notifications.map(item => {
    item.targetId = targets[item.userId].targetId
    item.scope = targets[item.userId].scope
    item.save().then(result => {
      result.destroy()
    })
  })
  return notifications
}

/**
 * Send template message to a user using wechat
 * @param {object} data
 * @param {array} targets
 * @return {object} Notification
 */
export const sendNotifications = async (
  { title, data, url } = data,
  targets
) => {
  let users = targets.reduce((obj, item) => {
    obj[item.userId] = item
    return obj
  }, {})

  let notifications = await findByUserIds(users)
  let template = CONFIG.wechat.templates[title]

  if (notifications && template) {
    notifications.map(notification => {
      let toUrl = url
      if (typeof url === 'function') {
        toUrl = url(users[notification.userId])
      }
      console.log(
        `Sending notification ${title} to ${notification.userId} at ${toUrl}`
      )
      $wechat.sendTemplateMessage(
        notification.openId,
        notification.formId,
        template.template_id,
        toUrl,
        data
      )
    })
  }
  return notifications.map(({ userId }) => {
    return userId
  })
}
